package com.briup.day08;

import java.util.Random;

/**
 * 动物类
 */
public class Animal {
    // 年龄
    private int age;
    // 性别
    private String gender;

    public Animal() {
        System.out.println("================这是Animal类的构造器==================");
    }

    public Animal(int age, String gender) {
        this.age = age;
        this.gender = gender;
    }

    /*
    在属性私有化之后，必须给对应的属性提供get/set方法
     因为属性私有化之后，在类外就无法通过对象直接操作属性，
     但是如果我们在类内部对外提供公开的访问属性的方法（get/set），
     那么我们就可以直接在类外通过这些方法进行访问属性，
     同时也可以将属性操作的过程进行封装，程序员/用户在需要时只用调用方法即可，
     不需要自己单独的对属性值进行设置，也无需关心属性是如何完成值的设置的
     */
    public String getAge() {
        return String.format("当前为%s岁", age);
    }

    public void setAge(int age) {
        // this是当前正在被创建的对象
        this.age = age;
    }

    public String getGender() {
        return "当前的性别为:" + gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void eat() {
        System.out.println("动物都需要进食");
    }

    public void sleep() {
        System.out.println("动物都需要休眠");
    }
}

// 如何表现Tiger是一个Animal
// 继承（class A extends B）能在Java中体现出 A is a B的关系
// 继承关系确定后，子类能够获取到父类中所有其能够访问的成员
class Tiger extends Animal {

    private static Random random = new Random();
    private static String[] genders = {"雄性", "雌性"};

    public Tiger() {
        // 在子类所有构造器的第一行，默认调用了父类的无参构造器，在此时super表示的是父类的对象
        // super()表示的是父类的无参构造器，如果要调用父类的其他参数构造器，
        // 那么只需要修改()内的参数传输个数即可
        super(0, genders[random.nextInt(2)]);
    }

    public Tiger(int age, String gender) {
        // 属性赋值，但是属性是定义在父类中，并且属性已经私有化
        // 方案一：借助于从父类中继承下来的set方法
        setAge(age);
        setGender(gender);
        // 方案二：借助于父类的构造器进行赋值，在子类的构造器中默认调用了父类的无参构造器
        // 具体情况看Tiger类无参构造器
    }

    /*
    如果子类对于从父类中继承下来的方法不满意，那么就可以使用方法的重写，
     重新设计该方法的实现逻辑
     @Override注解作用：检查你当前对方法的重写是否符合规则
     方法重写的规则：
        1、方法的重写只能存在于子类继承父类的方法，对该方法的实现逻辑/方法体
        进行重写
        2、方法的重写不能修改方法的名字，同时不能修改方法的参数列表
        ==>修改参数列表就构成了方法的重载
        3、重写通常情况下是不能修改方法的返回值类型，除非是将返回值类型有父类类型
        修改为确切的子类类型；如果原来返回值为void或基本数据类型，那么返回值类型
        就不能修改
        4、重写如果要修改权限修饰符，那么只能将权限修饰符放大，而不能缩小，
        如将protected修改为public
     方法的重载：
        1、方法的重载只能存在于一个类中，如果某一个方案存在多种情况的时候，我们
        将这些情况的方案方法其同一个名字，然后通过方法的参数列表不同来区分方法
        2、方法参数列表不同，指的是方法的参数个数以及参数类型不同
        3、方法的重载不涉及方法的返回值类型，重载后的所有方法返回值类型都不同也没有问题
     */
    @Override
    public void eat() {
        System.out.println("老虎只能吃肉");
    }
}

class Test {
    public static void main(String[] args) {
        // 在创建对象时，必须要调用对应类的构造器
        Tiger t = new Tiger();
        t.eat();
        t.sleep();
        System.out.println(t.getAge());
        System.out.println(t.getGender());
        Tiger t2 = new Tiger(10, "雄性");
        System.out.println(t2.getAge());
        System.out.println(t2.getGender());
        Tiger t3 = new Tiger(20, "雌性");
        System.out.println(t2.getAge());
        System.out.println(t2.getGender());
    }
}
